package asteroids.model;

import be.kuleuven.cs.som.annotate.Basic;
import asteroids.Util;

/**
 * A subclass of the Vector-class, specifically for Speed.
 * @author Martin & Anton
 * @invar 	The total speed will never exceed it's maximum speed, nor will the values be null.
 * 			| isValidSpeed(getX(),getY(), max_speed)
 */
public class Speed extends Vector {

	/**
	 * This creates a speed, with the max speed as the given speed.
	 * @param x
	 * @param y
	 * @param max_speed
	 * @effect	Ship(x,y)
	 * @post	The max speed will be set as the given max speed.
	 * 			| (new this).max_speed == max_speed
	 */
	public Speed(double x, double y, double max_speed) {
		super(0, 0);
		this.max_speed = max_speed;
		setSpeed(x,y);
	}
	
	private final double max_speed;
	
	/**
	 * Method to check if a given speed is valid
	 * @param inputX
	 * @param inputY
	 * @return true if it's valid (useful double, speed doesn't exceed the maximum speed, else false.
	 * 			| result == (Util.isValidDouble(x) && Util.isValidDouble(y) && 
	 * 			|				(Math.pow(inputX, 2) + Math.pow(inputY, 2) <= Math.pow(max_speed, 2)))
	 */
	private boolean isValidSpeed(double inputX, double inputY){
		return isValidSpeed(inputX,inputY,this.max_speed);
	}
	
	/**
	 * Method to check if a given speed is valid
	 * @param inputX
	 * @param inputY
	 * @param maxspeed
	 * @return true if it's valid (useful double, speed doesn't exceed the maximum speed, else false.
	 * 			| result == (Util.isValidDouble(x) && Util.isValidDouble(y) && 
	 * 			|				(Math.pow(inputX, 2) + Math.pow(inputY, 2) <= Math.pow(max_speed, 2)))
	 */
	public static boolean isValidSpeed(double inputX, double inputY, double maxspeed){
		if(Util.isValidDouble(inputX) && Util.isValidDouble(inputY))
			return Math.pow(inputX, 2) + Math.pow(inputY, 2) <= Math.pow(maxspeed, 2);
		else{
			return false;
		}
	}
	
	
	/**
	 * Method to change the speed. This method overwrites super.setCoord(x,y)
	 * @param x
	 * @param y
	 * @post	If the given speed is valid, specified by isValidSpeed, the speed will be set as the input.
	 * 			| if(isValidSpeed(x,y))
	 * 			|	then ((new this).getX() == x) && ((new this).getY() == y)
	 * @post	If the given speed is too high, but are valid numbers, then the speed will be set with the same direction of the given speed,
	 * 				but the total speed will be the maximum speed.
	 * 			| if(Util.isValidDouble(x) && Util.isValidDouble(y))
	 * 			| 	then (new this).getX() == x / ((Math.pow(inputX, 2) + Math.pow(inputY, 2))/ (Math.pow(max_speed, 2))) &&
	 * 			|		(new this).getY() == y / ((Math.pow(inputX, 2) + Math.pow(inputY, 2))/ (Math.pow(max_speed, 2)))
	 * @post	If one if the given numbers is invalid, specified by Util.isValidDouble of Vector, then nothing will happen.
	 * 			| if((!Util.isValidDouble(x) || !Util.isValidDouble(y))
	 * 			|	then (new this).getX() = this.getX() && (new this).getY() == this.getY()
	 */
	@Basic
	public void setSpeed(double x, double y) {
		if(isValidSpeed(x,y)){
			setX(x);
			setY(y);
		}
		else if(Util.isValidDouble(x) && Util.isValidDouble(y)){
			setX(x / Math.sqrt((Math.pow(x, 2) + Math.pow(y, 2))/ (Math.pow(max_speed, 2))));
			setY(y / Math.sqrt((Math.pow(x, 2) + Math.pow(y, 2))/ (Math.pow(max_speed, 2))));
		}
	}
	
	/**
	 * Method to change the X-speed.
	 * @param input
	 * @post	If with the given X-speed the speed of light is not exceeded, X is changed into the new X-speed.
	 * 			| if(isValidSpeed(input,this.getY()))
	 * 			| 	(new this).getX() = input;
	 * @post	If the given X-speed is valid, but will exceed the maximum speed, the input will be decreased, for the speed to be exactly the maximum speed.
	 * 			| if(!isValidSpeed(input, this.getY()) && Util.isValidDouble(input))
	 * 			|	(new this.getX() = Math.sqrt(Math.pow(max_speed, 2) - Math.pow(this.getY(), 2));
	 * @post 	If the given input is not valid, nothing will happen.
	 * 			| if(!Util.isValidDouble(input))
	 * 			| 	(new this).getX() = this.getX()
	 */
	public void setX(double input){
		if(isValidSpeed(input,this.getY())){
			super.setX(input);
		}
		else{
			if (Util.isValidDouble(input)){
				super.setX(Math.sqrt(Math.pow(max_speed, 2) - Math.pow(this.getY(), 2)));
			}
		}
	}
	
	/**
	 * Method to change the Y-speed.
	 * @param input
	 * @post	If with the given Y-speed the speed of light is not exceeded, Y is changed into the new Y-speed.
	 * 			| if(isValidSpeed(this.getX(),input))
	 * 			| 	(new this).getY() = input;
	 * @post	If the given Y-speed is valid, but will exceed the maximum speed, the input will be decreased, 
	 * 			for the speed to be exactly the maximum speed.
	 * 			| if(!isValidSpeed(this.getX(),input) && Util.isValidDouble(input))
	 * 			|	(new this.getY() = Math.sqrt(Math.pow(max_speed, 2) - Math.pow(this.getX(), 2));
	 * @post 	If the given input is not valid, nothing will happen.
	 * 			| if(!Util.isValidDouble(input))
	 * 			| 	(new this).getY() = this.getY()
	 */
	public void setY(double input) {
		if(isValidSpeed(this.getX(),input)){
			super.setY(input);
		}
		else{
			if (Util.isValidDouble(input)){
				super.setY(Math.sqrt(Math.pow(max_speed, 2) - Math.pow(this.getX(), 2)));
			}
		}
	}
	
	/**
	 * Returns the total speed.
	 * @return Math.sqrt(Math.pow(getX(), 2) + Math.pow(getY(), 2))
	 */
	public double getTotalSpeed(){
		return Math.sqrt(Math.pow(getX(), 2) + Math.pow(getY(), 2));
	}
}
